[go: nahoru, domu]

blob: 8f397d8c5d20b0430f18209c8ebf900279e8d5a3 [file] [log] [blame]
sverrir@chromium.org19478682009-07-13 16:11:081// Copyright (c) 2006-2009 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.
4
5#include "printing/image.h"
6
7#include "base/file_util.h"
8#include "base/gfx/png_decoder.h"
9#include "base/gfx/png_encoder.h"
10#include "base/gfx/rect.h"
11#include "base/string_util.h"
12#include "printing/native_metafile.h"
13#include "skia/ext/platform_device.h"
14
15#if defined(OS_WIN)
16#include "base/gfx/gdi_util.h" // EMF support
17#endif
18
19printing::Image::Image(const std::wstring& filename) : ignore_alpha_(true) {
20 std::string data;
21 file_util::ReadFileToString(filename, &data);
22 std::wstring ext = file_util::GetFileExtensionFromPath(filename);
23 bool success = false;
24 if (LowerCaseEqualsASCII(ext, "png")) {
25 success = LoadPng(data);
26 } else if (LowerCaseEqualsASCII(ext, "emf")) {
27 success = LoadMetafile(data);
28 } else {
29 DCHECK(false);
30 }
31 if (!success) {
32 size_.SetSize(0, 0);
33 row_length_ = 0;
34 data_.clear();
35 }
36}
37
38bool printing::Image::SaveToPng(const std::wstring& filename) {
39 DCHECK(!data_.empty());
40 std::vector<unsigned char> compressed;
41 bool success = PNGEncoder::Encode(&*data_.begin(),
42 PNGEncoder::FORMAT_BGRA,
43 size_.width(),
44 size_.height(),
45 row_length_,
46 true,
47 &compressed);
48 DCHECK(success && compressed.size());
49 if (success) {
50 int write_bytes = file_util::WriteFile(
51 filename,
52 reinterpret_cast<char*>(&*compressed.begin()), compressed.size());
53 success = (write_bytes == static_cast<int>(compressed.size()));
54 DCHECK(success);
55 }
56 return success;
57}
58
59double printing::Image::PercentageDifferent(const Image& rhs) const {
60 if (size_.width() == 0 || size_.height() == 0 ||
61 rhs.size_.width() == 0 || rhs.size_.height() == 0)
62 return 100.;
63
64 int width = std::min(size_.width(), rhs.size_.width());
65 int height = std::min(size_.height(), rhs.size_.height());
66 // Compute pixels different in the overlap
67 int pixels_different = 0;
68 for (int y = 0; y < height; ++y) {
69 for (int x = 0; x < width; ++x) {
70 uint32 lhs_pixel = pixel_at(x, y);
71 uint32 rhs_pixel = rhs.pixel_at(x, y);
72 if (lhs_pixel != rhs_pixel)
73 ++pixels_different;
74 }
75
76 // Look for extra right lhs pixels. They should be white.
77 for (int x = width; x < size_.width(); ++x) {
78 uint32 lhs_pixel = pixel_at(x, y);
79 if (lhs_pixel != Color(SK_ColorWHITE))
80 ++pixels_different;
81 }
82
83 // Look for extra right rhs pixels. They should be white.
84 for (int x = width; x < rhs.size_.width(); ++x) {
85 uint32 rhs_pixel = rhs.pixel_at(x, y);
86 if (rhs_pixel != Color(SK_ColorWHITE))
87 ++pixels_different;
88 }
89 }
90
91 // Look for extra bottom lhs pixels. They should be white.
92 for (int y = height; y < size_.height(); ++y) {
93 for (int x = 0; x < size_.width(); ++x) {
94 uint32 lhs_pixel = pixel_at(x, y);
95 if (lhs_pixel != Color(SK_ColorWHITE))
96 ++pixels_different;
97 }
98 }
99
100 // Look for extra bottom rhs pixels. They should be white.
101 for (int y = height; y < rhs.size_.height(); ++y) {
102 for (int x = 0; x < rhs.size_.width(); ++x) {
103 uint32 rhs_pixel = rhs.pixel_at(x, y);
104 if (rhs_pixel != Color(SK_ColorWHITE))
105 ++pixels_different;
106 }
107 }
108
109 // Like the WebKit ImageDiff tool, we define percentage different in terms
110 // of the size of the 'actual' bitmap.
111 double total_pixels = static_cast<double>(size_.width()) *
112 static_cast<double>(height);
113 return static_cast<double>(pixels_different) / total_pixels * 100.;
114}
115
116bool printing::Image::LoadPng(const std::string& compressed) {
117 int w;
118 int h;
119 bool success = PNGDecoder::Decode(
120 reinterpret_cast<const unsigned char*>(compressed.c_str()),
121 compressed.size(), PNGDecoder::FORMAT_BGRA, &data_, &w, &h);
122 size_.SetSize(w, h);
123 row_length_ = size_.width() * sizeof(uint32);
124 return success;
125}
126
127bool printing::Image::LoadMetafile(const std::string& data) {
128 DCHECK(!data.empty());
129#if defined(OS_WIN)
130 printing::NativeMetafile metafile;
131 metafile.CreateFromData(data.data(), data.size());
132 gfx::Rect rect(metafile.GetBounds());
133 // Create a temporary HDC and bitmap to retrieve the rendered data.
134 HDC hdc = CreateCompatibleDC(NULL);
135 BITMAPV4HEADER hdr;
136 DCHECK_EQ(rect.x(), 0);
137 DCHECK_EQ(rect.y(), 0);
138 DCHECK_GT(rect.width(), 0);
139 DCHECK_GT(rect.height(), 0);
140 size_ = rect.size();
141 gfx::CreateBitmapV4Header(rect.width(), rect.height(), &hdr);
142 void* bits;
143 HBITMAP bitmap = CreateDIBSection(hdc,
144 reinterpret_cast<BITMAPINFO*>(&hdr), 0,
145 &bits, NULL, 0);
146 DCHECK(bitmap);
147 DCHECK(SelectObject(hdc, bitmap));
148 skia::PlatformDevice::InitializeDC(hdc);
149 bool success = metafile.Playback(hdc, NULL);
150 row_length_ = size_.width() * sizeof(uint32);
151 size_t bytes = row_length_ * size_.height();
152 DCHECK(bytes);
153 data_.resize(bytes);
154 memcpy(&*data_.begin(), bits, bytes);
155 DeleteDC(hdc);
156 DeleteObject(bitmap);
157 return success;
158#else
159 NOTIMPLEMENTED();
160 return false;
161#endif
162}