OSDN Git Service

イニシャルコミット。
[marathon/ShapeFusion.git] / Shapes / utilities.cpp
1 /*
2  * This file is part of ShapeFusion (Copyright 2000 Tito Dal Canton)
3  *
4  * ShapeFusion is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * ShapeFusion is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with ShapeFusion; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18 #include "ShapesElements.h"
19 #include "utilities.h"
20
21 // convert an 8-bit ShapesBitmap to a RGB wxImage using the provided color table.
22 // <white_transparency> renders transparent pixels as white instead of using
23 // the chroma-key color. NOTE: this routine assumes valid pointers.
24 wxImage ShapesBitmapToImage(ShapesBitmap *bp, ShapesColorTable *ct, bool white_transparency)
25 {
26         int                             w = bp->Width(),
27                                         h = bp->Height();
28         bool                    transparency_enabled = bp->IsTransparent();
29         wxImage                 img(w, h);
30         unsigned char   *imgbuf = img.GetData(),
31                                         *inp = bp->Pixels(),
32                                         *outp = imgbuf;
33         unsigned int    colors_per_table = ct->ColorCount();
34
35         for (int i = 0; i < w * h; i++) {
36                 unsigned char   value = *inp++;
37
38                 if (value == 0 && transparency_enabled && white_transparency) {
39                         *outp++ = 255;
40                         *outp++ = 255;
41                         *outp++ = 255;
42                 } else if (value < colors_per_table) {
43                         ShapesColor     *color = ct->GetColor(value);
44
45                         *outp++ = color->Red() >> 8;
46                         *outp++ = color->Green() >> 8;
47                         *outp++ = color->Blue() >> 8;
48                 } else {
49                         wxLogError(wxT("[utilities ShapesBitmapToImage] Pixel value %u with just %u colors/table. Aborting"),
50                                                         value, colors_per_table);
51                         break;
52                 }
53         }
54         return img;
55 }
56
57 // create a wxBitmap thumbnail of the given wxImage. If the major wxImage
58 // dimension is greater than the specified thumbnail size, the wxImage
59 // will be scaled down (keeping its aspect ratio). If the wxImage is smaller,
60 // it will be just converted to a wxBitmap.
61 wxBitmap ImageThumbnail(wxImage &img, int tn_size, bool filtering)
62 {
63         int     w = img.GetWidth(),
64                 h = img.GetHeight();
65
66         // scale the wxImage down to thumbnail size if larger
67         if (w > tn_size || h > tn_size) {
68                 int     new_w, new_h;
69
70                 if (w > h) {
71                         new_w = tn_size;
72                         new_h = new_w * h / w;
73                         if (new_h < 1)
74                                 new_h = 1;
75                 } else {
76                         new_h = tn_size;
77                         new_w = new_h * w / h;
78                         if (new_w < 1)
79                                 new_w = 1;
80                 }
81
82                 if (filtering) {
83                         // wx doesn't allow nice scaling, so we supply here. The thing works this way:
84                         // 1) calculate where each source pixel will end up in the final image
85                         // 2) add the source pixel value to the destination pixel
86                         // 3) divide each destination pixel by the number of pixels
87                         //    that were added there.
88                         // It's nothing more than a brutal pixel-level average, but results are quite good.
89                         wxImage                 scaledimg(new_w, new_h);
90                         unsigned char   *src = img.GetData(),
91                                                         *srcp = src,
92                                                         *dst = scaledimg.GetData();
93                         unsigned int    pixcount = new_w * new_h,
94                                                         *tempbuf = new unsigned int[pixcount * 3],
95                                                         *countbuf = new unsigned int[pixcount];
96
97                         memset(tempbuf, 0, pixcount * 3 * sizeof(unsigned int));
98                         memset(countbuf, 0, pixcount * sizeof(unsigned int));
99                         // sum
100                         for (int y = 0; y < h; y++) {
101                                 unsigned int    dsty = (y * new_h) / h * new_w;
102
103                                 for (int x = 0; x < w; x++) {
104                                         unsigned int    i = x * new_w / w + dsty,
105                                                                         *tempp = &tempbuf[3 * i];
106
107                                         *tempp++ += *srcp++;
108                                         *tempp++ += *srcp++;
109                                         *tempp += *srcp++;
110                                         countbuf[i]++;
111                                 }
112                         }
113                         // divide
114                         unsigned int    *tempp = tempbuf,
115                                                         *countp = countbuf;
116                         unsigned char   *dstp = dst;
117
118                         for (unsigned int i = 0; i < pixcount; i++) {
119                                 unsigned int    count = *countp++;
120
121                                 if (count == 0) {
122                                         *dstp++ = 0;
123                                         *dstp++ = 0;
124                                         *dstp++ = 0;
125                                 } else {
126                                         *dstp++ = *tempp++ / count;
127                                         *dstp++ = *tempp++ / count;
128                                         *dstp++ = *tempp++ / count;
129                                 }
130                         }
131
132                         delete[] tempbuf;
133                         delete[] countbuf;
134                         return wxBitmap(scaledimg);
135                 } else {
136                         // ugly (but fast and simple) wx scaler
137                         img.Rescale(new_w, new_h);
138                         return wxBitmap(img);
139                 }
140         } else {
141                 return wxBitmap(img);
142         }
143 }
144
145 // create the "bad item" (red 'X') thumbnail
146 wxBitmap BadThumbnail(int tn_size)
147 {
148         wxImage                 newimg(tn_size, tn_size);
149         unsigned char   *imgbuf = newimg.GetData(), *p = imgbuf;
150
151         for (int y = 0; y < tn_size; y++) {
152                 for (int x = 0; x < tn_size; x++) {
153                         if (x == y || (tn_size - x - 1) == y || (x - 1) == y || (x + 1) == y
154                                 || (tn_size - x - 2) == y || (tn_size - x) == y) {
155                                 *p++ = 255;
156                                 *p++ = 0;
157                                 *p++ = 0;
158                         } else {
159                                 *p++ = 255;
160                                 *p++ = 255;
161                                 *p++ = 255;
162                         }
163                 }
164         }
165         return wxBitmap(newimg);
166 }
167
168 // compute (squared) distance between given RGB colours (range [0;1]).
169 // This is used to quantize imported bitmaps against collection palettes.
170 // The formula seems to work quite well even for photos and very bad
171 // destination palettes. It was taken from the article "Colour metric"
172 // by T. Riemersma, available under a Creative Commons license at
173 // http://www.compuphase.com/cmetric.htm.
174 float ColourDistance(float r1, float g1, float b1, float r2, float g2, float b2)
175 {
176         float   rMean = (r1 + r2) / 2.0,
177                         deltaR = r1 - r2,
178                         deltaG = g1 - g2,
179                         deltaB = b1 - b2;
180         
181         return (2.0+rMean)*deltaR*deltaR + 4.0*deltaG*deltaG + (2.0+1.0-rMean)*deltaB*deltaB;
182 }
183