Project

General

Profile

Download (10.5 KB) Statistics
| Branch: | Tag: | Revision:

magiccube / src / main / java / org / distorted / bandaged / BandagedCreatorWorkerThread.java @ 01e57154

1 7cb8d4b0 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2022 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Distorted is free software: you can redistribute it and/or modify                             //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Distorted is distributed in the hope that it will be useful,                                  //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19
20
package org.distorted.bandaged;
21
22
import android.app.Activity;
23
import android.content.Intent;
24
import android.graphics.Bitmap;
25
import android.net.Uri;
26
import android.widget.Toast;
27
28
import java.io.BufferedOutputStream;
29
import java.io.File;
30
import java.io.FileOutputStream;
31
import java.io.IOException;
32
import java.lang.ref.WeakReference;
33
import java.nio.ByteBuffer;
34
import java.nio.ByteOrder;
35
import java.util.Vector;
36
37
///////////////////////////////////////////////////////////////////////////////////////////////////
38
39
class BandagedCreatorWorkerThread extends Thread
40
  {
41
  private static Vector<WorkLoad> mBuffers;
42
  private static BandagedCreatorWorkerThread mThis=null;
43
  private static WeakReference<Activity> mWeakAct;
44
45
  private static class WorkLoad
46
    {
47
    ByteBuffer buffer;
48
    int width;
49
    int height;
50
    int numColors;
51
    String filename;
52
53
    WorkLoad(ByteBuffer buf, int w, int h, int n, String name)
54
      {
55
      buffer   = buf;
56
      width    = w;
57
      height   = h;
58
      numColors= n;
59
      filename = name;
60
      }
61
    }
62
63 ba52835a Leszek Koltunski
  private int mCreatedBufSize;
64
65 7cb8d4b0 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
66
67
  private BandagedCreatorWorkerThread()
68
    {
69
    }
70
71
///////////////////////////////////////////////////////////////////////////////////////////////////
72
73
  static void create(Activity act)
74
    {
75
    mWeakAct = new WeakReference<>(act);
76
77
    if( mThis==null )
78
      {
79
      mBuffers = new Vector<>();
80
      mThis = new BandagedCreatorWorkerThread();
81
      mThis.start();
82
      }
83
    }
84
85
///////////////////////////////////////////////////////////////////////////////////////////////////
86
87
  public void run()
88
    {
89
    WorkLoad load;
90
91
    while(true)
92
      {
93
      synchronized(mThis)
94
        {
95
        while( mBuffers.size()>0 )
96
          {
97
          load = mBuffers.remove(0);
98
          process(load);
99
          }
100
101
        try  { mThis.wait(); }
102
        catch(InterruptedException ex) { }
103
        }
104
      }
105
    }
106
107
///////////////////////////////////////////////////////////////////////////////////////////////////
108
109
  static void newBuffer(ByteBuffer buffer, int width, int height, int numColors, String filename)
110
    {
111
    synchronized(mThis)
112
      {
113
      WorkLoad load = new WorkLoad(buffer,width,height,numColors,filename);
114
      mBuffers.add(load);
115
      mThis.notify();
116
      }
117
    }
118
119
///////////////////////////////////////////////////////////////////////////////////////////////////
120
121 ba52835a Leszek Koltunski
  private int firstBlackPixel(byte[] tmp, int width)
122 7cb8d4b0 Leszek Koltunski
    {
123
    for(int i=0; i<width; i++)
124
      {
125 ba52835a Leszek Koltunski
      if( tmp[4*i]==0 && tmp[4*i+3]==-1 ) return i;
126
      }
127
128
    return -1;
129
    }
130
131
///////////////////////////////////////////////////////////////////////////////////////////////////
132
133
  private int lastBlackPixel(byte[] tmp, int width)
134
    {
135
    for(int i=width-1; i>=0; i--)
136
      {
137
      if( tmp[4*i]==0 && tmp[4*i+3]==-1 ) return i;
138 7cb8d4b0 Leszek Koltunski
      }
139
140 ba52835a Leszek Koltunski
    return -1;
141 7cb8d4b0 Leszek Koltunski
    }
142
143
///////////////////////////////////////////////////////////////////////////////////////////////////
144
145
  private int computeFirstRow(ByteBuffer buf, byte[] tmp, int width, int height)
146
    {
147
    int wBytes = 4*width;
148
149
    for(int i=0; i<height; i++)
150
      {
151
      buf.position(i*wBytes);
152
      buf.get(tmp);
153
154 ba52835a Leszek Koltunski
      if( firstBlackPixel(tmp,width)>=0 ) return i;
155 7cb8d4b0 Leszek Koltunski
      }
156
157 20b60ad9 Leszek Koltunski
    return 0;
158 7cb8d4b0 Leszek Koltunski
    }
159
160
///////////////////////////////////////////////////////////////////////////////////////////////////
161
162
  private int computeLastRow(ByteBuffer buf, byte[] tmp, int width, int height)
163
    {
164
    int wBytes = 4*width;
165
166
    for(int i=height-1; i>=0; i--)
167
      {
168
      buf.position(i*wBytes);
169
      buf.get(tmp);
170
171 ba52835a Leszek Koltunski
      if( firstBlackPixel(tmp,width)>=0 ) return i;
172 7cb8d4b0 Leszek Koltunski
      }
173
174 20b60ad9 Leszek Koltunski
    return width-1;
175 7cb8d4b0 Leszek Koltunski
    }
176
177
///////////////////////////////////////////////////////////////////////////////////////////////////
178
179 ba52835a Leszek Koltunski
  private int computeLeftColumn(ByteBuffer buf, byte[] tmp, int width, int firstrow, int lastrow)
180 7cb8d4b0 Leszek Koltunski
    {
181
    int wBytes = 4*width;
182 ba52835a Leszek Koltunski
    int currentBest = width;
183 7cb8d4b0 Leszek Koltunski
184 ba52835a Leszek Koltunski
    for(int i=firstrow; i<lastrow; i++)
185 7cb8d4b0 Leszek Koltunski
      {
186 ba52835a Leszek Koltunski
      buf.position(i*wBytes);
187
      buf.get(tmp);
188
189
      int pixel = firstBlackPixel(tmp,width);
190
      if( pixel>=0 && pixel<currentBest ) currentBest = pixel;
191 7cb8d4b0 Leszek Koltunski
      }
192
193 ba52835a Leszek Koltunski
    return currentBest;
194 7cb8d4b0 Leszek Koltunski
    }
195
196
///////////////////////////////////////////////////////////////////////////////////////////////////
197
198 ba52835a Leszek Koltunski
  private int computeRightColumn(ByteBuffer buf, byte[] tmp, int width, int firstrow, int lastrow)
199 7cb8d4b0 Leszek Koltunski
    {
200 ba52835a Leszek Koltunski
    int wBytes = 4*width;
201
    int currentBest = 0;
202 7cb8d4b0 Leszek Koltunski
203 ba52835a Leszek Koltunski
    for(int i=firstrow; i<lastrow; i++)
204 7cb8d4b0 Leszek Koltunski
      {
205 ba52835a Leszek Koltunski
      buf.position(i*wBytes);
206
      buf.get(tmp);
207
208
      int pixel = lastBlackPixel(tmp,width);
209
      if( pixel>=0 && pixel>currentBest ) currentBest = pixel;
210 7cb8d4b0 Leszek Koltunski
      }
211 ba52835a Leszek Koltunski
212
    return currentBest;
213 7cb8d4b0 Leszek Koltunski
    }
214
215
///////////////////////////////////////////////////////////////////////////////////////////////////
216 ba52835a Leszek Koltunski
// GL uses a coordinate system from mathematics; i.e. (0,0) is in the lower-left corner. 2D stuff
217
// has the origin on the upper-left corner; we have to flip our bitmap upside down!
218
//
219
// We also need to figure out the topmost and bottommost rows where the object starts and cut out
220
// a square section from the 'input' so that the object is vertically centralized.
221 7cb8d4b0 Leszek Koltunski
222 ba52835a Leszek Koltunski
  private ByteBuffer adjustBuffer(ByteBuffer input, byte[] tmp, int width, int height)
223 7cb8d4b0 Leszek Koltunski
    {
224 ba52835a Leszek Koltunski
    int firstRow   = computeFirstRow(input,tmp,width,height);
225
    int lastRow    = computeLastRow(input,tmp,width,height);
226
    int leftColumn = computeLeftColumn(input,tmp,width,firstRow,lastRow);
227
    int rightColumn= computeRightColumn(input,tmp,width,firstRow,lastRow);
228
229
    int rowHeight = lastRow-firstRow;
230
    int colWidth  = rightColumn-leftColumn;
231
    int size      = Math.max(rowHeight,colWidth);
232
    size = (int)(1.1f*size);
233
    int half = size/2;
234
    int centerX = (leftColumn+rightColumn)/2;
235
    int centerY = (firstRow+lastRow)/2;
236
    int sL=size, sR=size, sT=size, sB=size;
237
238
    if( centerX-half<    0 )
239
      {
240
      android.util.Log.e("D", "buffer encroaches on the left!   centerX="+centerX+" centerY="+centerY+" size="+size);
241
      sL = 2*centerX;
242
      }
243
    if( centerX+half>width )
244
      {
245
      android.util.Log.e("D", "buffer encroaches on the right!  centerX="+centerX+" centerY="+centerY+" size="+size);
246
      sR = 2*(width-centerX);
247
      }
248
    if( centerY-half<    0 )
249
      {
250
      android.util.Log.e("D", "buffer encroaches on the top!    centerX="+centerX+" centerY="+centerY+" size="+size);
251
      sT = 2*centerY;
252
      }
253
    if( centerY+half>height)
254
      {
255
      android.util.Log.e("D", "buffer encroaches on the bottom! centerX="+centerX+" centerY="+centerY+" size="+size);
256
      sB = 2*(height-centerY);
257
      }
258
/*
259
    if( sL==size && sR==size && sT==size && sB==size )
260
      {
261
      android.util.Log.e("D", "EVERYTHING ALL RIGHT centerX="+centerX+" centerY="+centerY+" size="+size);
262
      }
263
*/
264
    int minH = Math.min(sL,sR);
265
    int minV = Math.min(sT,sB);
266
    mCreatedBufSize = Math.min(minH,minV);
267
    half = mCreatedBufSize/2;
268
    int wBytes = 4*mCreatedBufSize;
269
    ByteBuffer output = ByteBuffer.allocateDirect(wBytes*mCreatedBufSize);
270 7cb8d4b0 Leszek Koltunski
    output.order(ByteOrder.LITTLE_ENDIAN);
271 ba52835a Leszek Koltunski
    int startRow = centerY+half;
272
    int distR = width-centerX-half;
273 7cb8d4b0 Leszek Koltunski
274 ba52835a Leszek Koltunski
    for(int i=0; i<mCreatedBufSize; i++)
275 7cb8d4b0 Leszek Koltunski
      {
276 ba52835a Leszek Koltunski
      input.position((startRow-i)*4*width + 4*distR );
277
      input.get(tmp,0,wBytes);
278 7cb8d4b0 Leszek Koltunski
      output.position(i*wBytes);
279 ba52835a Leszek Koltunski
      output.put(tmp,0,wBytes);
280 7cb8d4b0 Leszek Koltunski
      }
281
282
    output.rewind();
283
    return output;
284
    }
285
286
///////////////////////////////////////////////////////////////////////////////////////////////////
287
288
  private void process(WorkLoad load)
289
    {
290 ba52835a Leszek Koltunski
    int width  = load.width;
291
    int height = load.height;
292 7cb8d4b0 Leszek Koltunski
293
    byte[] tmp = new byte[4*width];
294
    ByteBuffer bufSquare = adjustBuffer(load.buffer,tmp,width,height);
295
    final String filename = load.filename;
296
    BufferedOutputStream bos =null;
297
    final Activity act = mWeakAct.get();
298
299
    try
300
      {
301
      bos = new BufferedOutputStream(new FileOutputStream(filename));
302 ba52835a Leszek Koltunski
      Bitmap bmp = Bitmap.createBitmap( mCreatedBufSize, mCreatedBufSize, Bitmap.Config.ARGB_8888);
303 eb6bccbd Leszek Koltunski
      bmp.copyPixelsFromBuffer(bufSquare);
304 7cb8d4b0 Leszek Koltunski
      bmp.compress(Bitmap.CompressFormat.PNG, 90, bos);
305
306
      BandagedCreatorActivity cact = (BandagedCreatorActivity)act;
307
      cact.iconCreationDone(bmp);
308
      }
309
    catch(final Exception ex)
310
      {
311
      act.runOnUiThread(new Runnable()
312
        {
313
        public void run()
314
          {
315
          Toast.makeText(act,
316
              "Saving to \n\n"+filename+"\n\n failed: "+"\n\n"+ex.getMessage() ,
317
              Toast.LENGTH_LONG).show();
318
          }
319
        });
320
      }
321
    finally
322
      {
323
      if(bos!=null)
324
        {
325
        try { bos.close(); }
326
        catch(IOException io) {}
327
        }
328
      }
329
330
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
331
    File f = new File(filename);
332
    Uri contentUri = Uri.fromFile(f);
333
    mediaScanIntent.setData(contentUri);
334
    act.sendBroadcast(mediaScanIntent);
335
    }
336
  }